home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / proc / procFork.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  14KB  |  513 lines

  1. /* 
  2.  *  procFork.c --
  3.  *
  4.  *    Routines to create new processes.  No monitor routines are required
  5.  *    in this file.  Synchronization to proc table entries is by a call
  6.  *    to the proc table monitor to get a PCB and calls to the family monitor
  7.  *    to put a newly created process into a process family.
  8.  *
  9.  * Copyright (C) 1985, 1988 Regents of the University of California
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/proc/procFork.c,v 9.11 91/11/15 21:06:46 kupfer Exp $ SPRITE (Berkeley)";
  21. #endif /* not lint */
  22.  
  23. #include <sprite.h>
  24. #include <mach.h>
  25. #include <list.h>
  26. #include <proc.h>
  27. #include <procInt.h>
  28. #include <sched.h>
  29. #include <status.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <sync.h>
  33. #include <sys.h>
  34. #include <timer.h>
  35. #include <vm.h>
  36. #include <prof.h>
  37. #include <procUnixStubs.h>
  38.  
  39. /*
  40.  * There is only one vfork sleep condition in the system.
  41.  * When a child does a Sync_Broadcast, all sleeping parents
  42.  * wake up, check the VFORKPARENT flag in their respective
  43.  * PCBs and all but one (hopefully) go back to sleep.
  44.  * If the contention level is too high we can put a condition lock
  45.  * in each PCB, but this requires recompiling most of the world
  46.  * so lets try the easy way first.
  47.  */
  48. static Sync_Condition vforkCondition;
  49. static Sync_Lock vforkLock;
  50. #define LOCKPTR &vforkLock
  51.  
  52. static ReturnStatus    InitUserProc _ARGS_((Proc_ControlBlock *procPtr,
  53.                 Proc_ControlBlock *parentProcPtr,
  54.                 Boolean shareHeap, Boolean vforkFlag));
  55.  
  56.  
  57. /*
  58.  *----------------------------------------------------------------------
  59.  *
  60.  * Proc_Fork --
  61.  *
  62.  *    Process the fork system call.
  63.  *
  64.  * Results:
  65.  *    None.
  66.  *
  67.  * Side effects:
  68.  *    None.
  69.  *
  70.  *----------------------------------------------------------------------
  71.  */
  72.  
  73. int
  74. Proc_Fork(shareHeap, pidPtr)
  75.     Boolean    shareHeap;
  76.     Proc_PID    *pidPtr;
  77. {
  78.     Proc_PID        *newPidPtr;
  79.     int            numBytes;
  80.     ReturnStatus    status;
  81.     
  82.     /*
  83.      * Make the pointer to the process id that is to be returned accessible.
  84.      */
  85.  
  86.     Vm_MakeAccessible(VM_OVERWRITE_ACCESS, 
  87.               sizeof(Proc_PID), (Address) pidPtr,
  88.               &numBytes, (Address *) &newPidPtr);
  89.     if (numBytes < sizeof(Proc_PID)) {
  90.     return(SYS_ARG_NOACCESS);
  91.     }
  92.  
  93.     /*
  94.      * Start up the new process.  The PC where to begin execution doesn't 
  95.      * matter since it has already been stored in the proc table entry before
  96.      * we were called.
  97.      */
  98.  
  99.     status = Proc_NewProc((Address) 0, PROC_USER, shareHeap, newPidPtr,
  100.               (char *)NIL, FALSE);
  101.  
  102.     Vm_MakeUnaccessible((Address) newPidPtr, numBytes);
  103.  
  104.     return(status);
  105. }
  106.  
  107.  
  108. /*
  109.  *----------------------------------------------------------------------
  110.  *
  111.  * Proc_Vfork --
  112.  *
  113.  *    Process the vfork system call.
  114.  *
  115.  * Results:
  116.  *    None.
  117.  *
  118.  * Side effects:
  119.  *    None.
  120.  *
  121.  *----------------------------------------------------------------------
  122.  */
  123.  
  124. int
  125. Proc_Vfork()
  126. {
  127.     ReturnStatus    status;
  128.     Proc_PID newPid;
  129.  
  130.     status = Proc_NewProc((Address) 0, PROC_USER, FALSE, &newPid,
  131.               (char *) NIL, TRUE);
  132.     if (status != SUCCESS) {
  133.     Mach_SetErrno(Compat_MapCode(status));
  134.     return -1;
  135.     }
  136.     return (int) newPid;
  137. }
  138.  
  139.  
  140. /*
  141.  * ----------------------------------------------------------------------------
  142.  *
  143.  * Proc_VforkWakeup
  144.  *
  145.  *    Called by vfork'd child to wakeup waiting parent
  146.  *      (when child dies or execs). Caller must hold a lock
  147.  *      on the child's PCB entry (ie. must have called Proc_Lock()).
  148.  *
  149.  * Results:
  150.  *    None.
  151.  *
  152.  * Side effects:
  153.  *    Will make parent process runnable.
  154.  *
  155.  * ----------------------------------------------------------------------------
  156.  */
  157.  
  158. void
  159. Proc_VforkWakeup(procPtr)
  160. Proc_ControlBlock     *procPtr;
  161. {
  162.     Proc_ControlBlock     *parentProcPtr;
  163.  
  164.     parentProcPtr = Proc_GetPCB(procPtr->parentID);
  165.     Proc_Lock(parentProcPtr);
  166.     if (!(parentProcPtr->genFlags & PROC_VFORKPARENT)) {
  167.     panic("VForkWakeup called but VFORKPARENT flag == 0.");
  168.     }
  169.     parentProcPtr->genFlags &= ~PROC_VFORKPARENT;
  170.     Proc_Unlock(parentProcPtr);
  171.  
  172.     LOCK_MONITOR;
  173.     Sync_Broadcast(&vforkCondition);
  174.     UNLOCK_MONITOR;
  175.  
  176.     procPtr->genFlags &= ~PROC_VFORKCHILD;
  177.  
  178. }
  179.  
  180.  
  181. /*
  182.  * ----------------------------------------------------------------------------
  183.  *
  184.  * Proc_NewProc --
  185.  *
  186.  *    Allocates a PCB and initializes it.
  187.  *
  188.  * Results:
  189.  *    Pointer to process control block for created process.
  190.  *
  191.  * Side effects:
  192.  *    PCB initialized and made runnable.
  193.  *
  194.  * ----------------------------------------------------------------------------
  195.  */
  196.  
  197. ReturnStatus
  198. Proc_NewProc(PC, procType, shareHeap, pidPtr, procName, vforkFlag)
  199.     Address     PC;        /* The program counter where to start. */
  200.     int        procType;    /* One of PROC_KERNEL or PROC_USER. */
  201.     Boolean    shareHeap;    /* TRUE if share heap, FALSE if not. */
  202.     Proc_PID    *pidPtr;    /* A pointer to where to return the process
  203.                    ID in. */
  204.     char    *procName;    /* Name for process control block */
  205.     Boolean     vforkFlag;      /* Added for vfork */
  206. {
  207.     ReturnStatus    status;
  208.     Proc_ControlBlock     *procPtr;    /* The new process being created */
  209.     Proc_ControlBlock     *parentProcPtr;    /* The parent of the new process,
  210.                      * the one that is making this call */
  211.     Boolean        migrated = FALSE;
  212.  
  213.     parentProcPtr = Proc_GetActualProc();
  214.  
  215.     if (parentProcPtr->genFlags & PROC_FOREIGN) {
  216.     migrated = TRUE;
  217.     }
  218.  
  219.     procPtr = ProcGetUnusedPCB();
  220.     if (pidPtr != (Proc_PID *) NIL) {
  221.     *pidPtr        = procPtr->processID;
  222.     }
  223.  
  224.     procPtr->Prof_Scale = 0;
  225.     Prof_Enable(procPtr, parentProcPtr->Prof_Buffer, 
  226.         parentProcPtr->Prof_BufferSize, parentProcPtr->Prof_Offset,
  227.     parentProcPtr->Prof_Scale);
  228.  
  229.     procPtr->processor        = parentProcPtr->processor;
  230.     procPtr->genFlags         |= procType;
  231.     if (vforkFlag) {
  232.     procPtr->genFlags |= PROC_VFORKCHILD;
  233.     }
  234.     procPtr->syncFlags        = 0;
  235.     procPtr->schedFlags        = 0;
  236.     procPtr->exitFlags        = 0;
  237.  
  238.     if (!migrated) {
  239.     procPtr->parentID     = parentProcPtr->processID;
  240.     } else {
  241.     procPtr->parentID     = parentProcPtr->peerProcessID;
  242.     }
  243.     procPtr->familyID         = parentProcPtr->familyID;
  244.     procPtr->userID         = parentProcPtr->userID;
  245.     procPtr->effectiveUserID     = parentProcPtr->effectiveUserID;
  246.  
  247.     procPtr->billingRate     = parentProcPtr->billingRate;
  248.     procPtr->recentUsage     = 0;
  249.     procPtr->weightedUsage     = 0;
  250.     procPtr->unweightedUsage     = 0;
  251.  
  252.     procPtr->kernelCpuUsage.ticks     = timer_TicksZeroSeconds;
  253.     procPtr->userCpuUsage.ticks     = timer_TicksZeroSeconds;
  254.     procPtr->childKernelCpuUsage.ticks = timer_TicksZeroSeconds;
  255.     procPtr->childUserCpuUsage.ticks     = timer_TicksZeroSeconds;
  256.     procPtr->numQuantumEnds    = 0;
  257.     procPtr->numWaitEvents    = 0;
  258.     procPtr->event        = NIL;
  259.  
  260.     procPtr->kcallTable        = mach_NormalHandlers;
  261.     procPtr->unixProgress    = parentProcPtr->unixProgress;
  262.  
  263.     /* 
  264.      * Free up the old argument list, if any.  Note, this could be put
  265.      * in Proc_Exit, but is put here for consistency with the other
  266.      * reinitializations of control block fields.  
  267. p     */
  268.  
  269.     if (procPtr->argString != (Address) NIL) {
  270.     free((Address) procPtr->argString);
  271.     procPtr->argString = (Address) NIL;
  272.     }
  273.  
  274.     /*
  275.      * Create the argument list for the child.  If no name specified, take
  276.      * the list from the parent.  If one is specified, just make a one-element
  277.      * list containing that name.
  278.      */
  279.     if (procName != (char *)NIL) {
  280.     procPtr->argString = (char *) malloc(strlen(procName) + 1);
  281.     (void) strcpy(procPtr->argString, procName);
  282.     } else if (parentProcPtr->argString != (Address) NIL) {
  283.     procPtr->argString =
  284.         (char *) malloc(strlen(parentProcPtr->argString) + 1);
  285.     (void) strcpy(procPtr->argString, parentProcPtr->argString);
  286.     }
  287.  
  288.     if (!migrated) {
  289.     if (ProcFamilyInsert(procPtr, procPtr->familyID) != SUCCESS) {
  290.         panic("Proc_NewProc: ProcFamilyInsert failed\n");
  291.     }
  292.     }
  293.  
  294.     /*
  295.      *  Initialize our child list to remove any old links.
  296.      *  If not migrated, insert this PCB entry into the list
  297.      *  of children of our parent.
  298.      */
  299.     List_Init((List_Links *) procPtr->childList);
  300.     if (!migrated) {
  301.     List_Insert((List_Links *) &(procPtr->siblingElement), 
  302.             LIST_ATREAR(parentProcPtr->childList));
  303.     }
  304.     Sig_Fork(parentProcPtr, procPtr);
  305.  
  306.     Vm_ProcInit(procPtr);
  307.  
  308.     /*
  309.      * If the process is migrated, setup its process state on the home node.
  310.      */
  311.     if (migrated) {
  312.     status = ProcRemoteFork(parentProcPtr, procPtr);
  313.     if (status != SUCCESS) {
  314.         /*
  315.          * We couldn't fork on the home node, so free up the new
  316.          * process that we were in the process of allocating.
  317.          */
  318.  
  319.         Proc_Unlock(procPtr);
  320.         ProcFreePCB(procPtr);
  321.  
  322.         return(status);
  323.     }
  324.  
  325.     /*
  326.      * Change the returned process ID to be the process ID on the home
  327.      * node.
  328.      */
  329.     if (pidPtr != (Proc_PID *) NIL) {
  330.         *pidPtr = procPtr->peerProcessID;
  331.     }
  332.     } else {
  333.     procPtr->peerHostID = NIL;
  334.     procPtr->peerProcessID = NIL;
  335.     }
  336.  
  337.     /*
  338.      * Set up the virtual memory of the new process.
  339.      */
  340.  
  341.     if (procType == PROC_KERNEL) {
  342.     status = Mach_SetupNewState(procPtr, (Mach_State *)NIL,
  343.                     Sched_StartKernProc, PC, FALSE);
  344.     if (status != SUCCESS) {
  345.         /*
  346.          * We are out of kernel stacks.
  347.          */
  348.         Proc_Unlock(procPtr);
  349.         ProcFreePCB(procPtr);
  350.         return(status);
  351.     }
  352.     } else {
  353.     status = InitUserProc(procPtr, parentProcPtr, shareHeap, vforkFlag);
  354.     if (status != SUCCESS) {
  355.         /*
  356.          * We couldn't allocate virtual memory, so free up the new
  357.          * process that we were in the process of allocating.
  358.          */
  359.  
  360.         if (!migrated) {
  361.         ProcFamilyRemove(procPtr);
  362.         List_Remove((List_Links *) &(procPtr->siblingElement));
  363.         }
  364.         Proc_Unlock(procPtr);
  365.         ProcFreePCB(procPtr);
  366.  
  367.         return(status);
  368.     }
  369.     }
  370.  
  371.     /*
  372.      * Mark ourselves waiting, if necessary
  373.      */
  374.     if (vforkFlag) {
  375.     Proc_Lock(parentProcPtr);
  376.     parentProcPtr->genFlags |= PROC_VFORKPARENT;
  377.     Proc_Unlock(parentProcPtr);
  378.     }
  379.  
  380.     /*
  381.      * Set up the environment of the process.
  382.      */
  383.  
  384.     if (!migrated) {
  385.     ProcSetupEnviron(procPtr);
  386.     }
  387.     
  388.     /*
  389.      * Have the new process inherit filesystem state.
  390.      */
  391.     Fs_InheritState(parentProcPtr, procPtr);
  392.  
  393.     /*
  394.      * Return PROC_CHILD_PROC to the newly created process.
  395.      */
  396.     if (procPtr->unixProgress == PROC_PROGRESS_NOT_UNIX) {
  397.     Mach_SetReturnVal(procPtr, (vforkFlag ? 0 : (int) PROC_CHILD_PROC), 1);
  398.     } else {
  399.     Mach_SetReturnVal(procPtr, 0, 1);
  400.     }
  401.  
  402.     /* 
  403.      * Now that we're done messing with the PCB, unlock it.  Maybe this 
  404.      * could get moved up to happen earlier in the function, but there's 
  405.      * probably no harm to delaying until now.
  406.      */
  407.     Proc_Unlock(procPtr);
  408.  
  409.     /*
  410.      * Put the process on the ready queue.
  411.      */
  412.     Sched_MakeReady(procPtr);
  413.  
  414.     /*
  415.      * Now make the parent wait until child exec`s or exits
  416.      */
  417.     if (vforkFlag) {
  418.     LOCK_MONITOR;
  419.     while (parentProcPtr->genFlags & PROC_VFORKPARENT) {
  420.         Sync_Wait(&vforkCondition, FALSE);
  421.     }
  422.     UNLOCK_MONITOR;
  423.     }
  424.  
  425.     return(SUCCESS);
  426. }
  427.  
  428.  
  429. /*
  430.  *----------------------------------------------------------------------
  431.  *
  432.  * InitUserProc --
  433.  *
  434.  *    Initalize the state for a user process.  This involves allocating
  435.  *    the segments for the new process.
  436.  *
  437.  * Results:
  438.  *    None.
  439.  *
  440.  * Side effects:
  441.  *    None.
  442.  *
  443.  *----------------------------------------------------------------------
  444.  */
  445.  
  446. static ReturnStatus
  447. InitUserProc(procPtr, parentProcPtr, shareHeap, vforkFlag)
  448.     register    Proc_ControlBlock    *procPtr;    /* PCB to initialized.*/
  449.     register    Proc_ControlBlock    *parentProcPtr;    /* Parent's PCB. */
  450.     Boolean                shareHeap;    /* TRUE => share heap
  451.                              * with parent. */
  452.     Boolean                vforkFlag;    /* TRUE => share all
  453.                              * segs with parent. */
  454. {
  455.     ReturnStatus    status;
  456.  
  457.     /*
  458.      * Set up a kernel stack for the process.
  459.      */
  460.     status = Mach_SetupNewState(procPtr, parentProcPtr->machStatePtr,
  461.                 Sched_StartUserProc, (Address)NIL, TRUE);
  462.     if (status != SUCCESS) {
  463.     return(status);
  464.     }
  465.  
  466.     /*
  467.      * Initialize all of the segments.  The system segment is the standard one.
  468.      * The code segment is the same as the parent process.  The stack segment
  469.      * is a copy of the parents, unless vforkFlag == TRUE in which case
  470.      * the ref count is boosted.  Finally the heap segment is either a copy
  471.      * or the same as the parent depending on the share heap flag.
  472.      */
  473.  
  474.     procPtr->vmPtr->segPtrArray[VM_SYSTEM] = (Vm_Segment *) NIL;
  475.  
  476.     if (vforkFlag) {
  477.     Vm_SegmentIncRef(parentProcPtr->vmPtr->segPtrArray[VM_STACK], procPtr);
  478.     procPtr->vmPtr->segPtrArray[VM_STACK] = 
  479.                 parentProcPtr->vmPtr->segPtrArray[VM_STACK];
  480.     } else {
  481.     status = Vm_SegmentDup(parentProcPtr->vmPtr->segPtrArray[VM_STACK],
  482.             procPtr, &(procPtr->vmPtr->segPtrArray[VM_STACK]));
  483.     if (status != SUCCESS) {
  484.         Mach_FreeState(procPtr);
  485.         return(status);
  486.     }
  487.     }
  488.  
  489.     if (shareHeap || vforkFlag) {
  490.     Vm_SegmentIncRef(parentProcPtr->vmPtr->segPtrArray[VM_HEAP], procPtr);
  491.     procPtr->vmPtr->segPtrArray[VM_HEAP] = 
  492.                 parentProcPtr->vmPtr->segPtrArray[VM_HEAP];
  493.     } else {
  494.     status = Vm_SegmentDup(parentProcPtr->vmPtr->segPtrArray[VM_HEAP],
  495.                procPtr, &(procPtr->vmPtr->segPtrArray[VM_HEAP]));
  496.     if (status != SUCCESS) {
  497.         Vm_SegmentDelete(procPtr->vmPtr->segPtrArray[VM_STACK], procPtr);
  498.         Mach_FreeState(procPtr);
  499.         return(status);
  500.     }
  501.     }
  502.  
  503.     if (parentProcPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  504.     Vm_CopySharedMem(parentProcPtr, procPtr);
  505.     }
  506.  
  507.     Vm_SegmentIncRef(parentProcPtr->vmPtr->segPtrArray[VM_CODE], procPtr);
  508.     procPtr->vmPtr->segPtrArray[VM_CODE] =
  509.                 parentProcPtr->vmPtr->segPtrArray[VM_CODE];
  510.  
  511.     return(SUCCESS);
  512. }
  513.